

//行为型模式分为类行为模式和对象行为模式，
// 前者采用继承机制来在类间分派行为，后者采用组合或聚合在对象间分配行为。
// 由于组合关系或聚合关系比继承关系耦合度低，满足“合成复用原则”，
// 所以对象行为模式比类行为模式具有更大的灵活性。

// 模板方法（Template Method）模式的定义如下：
// 定义一个操作中的算法骨架，而将算法的一些步骤延迟到子类中，
// 使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。
// 它是一种类行为型模式。

// 该模式的主要优点如下。
// 它封装了不变部分，扩展可变部分。它把认为是不变部分的算法封装到父类中实现，
//而把可变部分算法由子类继承实现，便于子类继续扩展。
// 它在父类中提取了公共的部分代码，便于代码复用。
// 部分方法是由子类实现的，因此子类可以通过扩展方式增加相应的功能，符合开闭原则。

// 该模式的主要缺点如下。
// 对每个不同的实现都需要定义一个子类，这会导致类的个数增加，系统更加庞大，
//设计也更加抽象，间接地增加了系统实现的复杂度。
// 父类中的抽象方法由子类实现，子类执行的结果会影响父类的结果，这导致一种反向的控制结构，它提高了代码阅读的难度。
// 由于继承关系自身的缺点，如果父类添加新的抽象方法，则所有子类都要改一遍。

public class StudyAbroadProcess {
    public static void main(String[] args) {
        //为什么用父类定义，而不用子类
        StudyAbroad tm = new StudyInAmerica();
        tm.TemplateMethod();
    }
}

//抽象类: 出国留学
abstract class StudyAbroad {
    public void TemplateMethod() //模板方法
    {
        LookingForSchool(); //索取学校资料
        ApplyForEnrol();    //入学申请
        ApplyForPassport(); //办理因私出国护照、出境卡和公证
        ApplyForVisa();     //申请签证
        ReadyGoAbroad();    //体检、订机票、准备行装
        Arriving();         //抵达
    }

    public void ApplyForPassport() {
        System.out.println("三.办理因私出国护照、出境卡和公证：");
        System.out.println("  1）持录取通知书、本人户口簿或身份证向户口所在地公安机关申请办理因私出国护照和出境卡。");
        System.out.println("  2）办理出生公证书，学历、学位和成绩公证，经历证书，亲属关系公证，经济担保公证。");
    }

    public void ApplyForVisa() {
        System.out.println("四.申请签证：");
        System.out.println("  1）准备申请国外境签证所需的各种资料，包括个人学历、成绩单、工作经历的证明；个人及家庭收入、资金和财产证明；家庭成员的关系证明等；");
        System.out.println("  2）向拟留学国家驻华使(领)馆申请入境签证。申请时需按要求填写有关表格，递交必需的证明材料，缴纳签证。有的国家(比如美国、英国、加拿大等)在申请签证时会要求申请人前往使(领)馆进行面试。");
    }

    public void ReadyGoAbroad() {
        System.out.println("五.体检、订机票、准备行装：");
        System.out.println("  1）进行身体检查、免疫检查和接种传染病疫苗；");
        System.out.println("  2）确定机票时间、航班和转机地点。");
    }

    public abstract void LookingForSchool();//索取学校资料

    public abstract void ApplyForEnrol();   //入学申请

    public abstract void Arriving();        //抵达
}

//具体子类: 美国留学
class StudyInAmerica extends StudyAbroad {
    @Override
    public void LookingForSchool() {
        System.out.println("一.索取学校以下资料：");
        System.out.println("  1）对留学意向国家的政治、经济、文化背景和教育体制、学术水平进行较为全面的了解；");
        System.out.println("  2）全面了解和掌握国外学校的情况，包括历史、学费、学制、专业、师资配备、教学设施、学术地位、学生人数等；");
        System.out.println("  3）了解该学校的住宿、交通、医疗保险情况如何；");
        System.out.println("  4）该学校在中国是否有授权代理招生的留学中介公司？");
        System.out.println("  5）掌握留学签证情况；");
        System.out.println("  6）该国政府是否允许留学生合法打工？");
        System.out.println("  8）毕业之后可否移民？");
        System.out.println("  9）文凭是否受到我国认可？");
    }

    @Override
    public void ApplyForEnrol() {
        System.out.println("二.入学申请：");
        System.out.println("  1）填写报名表；");
        System.out.println("  2）将报名表、个人学历证明、最近的学习成绩单、推荐信、个人简历、托福或雅思语言考试成绩单等资料寄往所申请的学校；");
        System.out.println("  3）为了给签证办理留有充裕的时间，建议越早申请越好，一般提前1年就比较从容。");
    }

    @Override
    public void Arriving() {
        System.out.println("六.抵达目标学校：");
        System.out.println("  1）安排住宿；");
        System.out.println("  2）了解校园及周边环境。");
    }
}